/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef _MESSAGE_QUEUE_H_
#define _MESSAGE_QUEUE_H_

/**
 * @file message_queue.h
 * @brief 消息队列定义
*/
#include "nfc_osi_api.h"
#include "priority_queue.h"
#define MESSAGE_QUEUE_NAME_MAX_LEN 18
#define MESSAGE_QUEUE_MAX_THREAD_COUNT 1

/**
 * @brief 消息队列的消息处理函数定义
 *
 * @param what 消息类型
 * @param arg1 参数1, uint32_t类型
 * @param arg2 参数2, uint64_t类型
 * @param args 参数3, void*指针
 *
 * @return true: 需要调用cleanup释放args指针, false: 不调用cleanup释放指针
*/
typedef bool (*tMQ_HANDLE)(uint32_t what, uint32_t arg1, uint64_t arg2, void* args);

/**
 * @brief 消息队列的消息清理函数定义
 *
 * @note 用于释放消息队列中args指针指向的内存
 *
 * @param what 消息类型
 * @param arg1 参数1, uint32_t类型
 * @param arg2 参数2, uint64_t类型
 * @param args 参数3, void*指针
*/
typedef void (*tMQ_CLEANUP)(uint32_t what, uint32_t arg1, uint64_t arg2, void* args);

/**
 * @brief 消息队列的消息结构体定义
 * @note 支持携带参数，简单的参数可以使用arg1和arg2，复杂的参数使用args指针
*/
typedef struct {
    /** @brief 消息类型 */
    uint32_t what;
    /** @brief 参数1, uint32_t类型 */
    uint32_t arg1;
    /** @brief 参数2, uint64_t类型*/
    uint64_t arg2;
    /** @brief 参数3, void*指针 */
    void* args;
    /** @brief 消息处理函数指针 */
    tMQ_HANDLE handle;
    /** @brief 消息清理函数指针 */
    tMQ_CLEANUP cleanup;
} tMQ_MSG;

/**
 * @brief 消息队列的状态定义
 *
 * MQ_STATE_NOT_INIT -> MQ_STATE_INIT -> MQ_STATE_STARTING -> MQ_STATE_RUNNING |-> MQ_STATE_PREPARE_STOP -> MQ_STATE_STOPPED
 *                                                                             |-> MQ_STATE_STOPPING     -|
*/
typedef enum {
    /** @brief 未初始化 */
    MQ_STATE_NOT_INIT = 0,
    /** @brief 已初始化 */
    MQ_STATE_INIT,
    /** @brief 任务线程启动中 */
    MQ_STATE_STARTING,
    /** @brief 任务线程启动完成, 消息队列已经可以正常工作 */
    MQ_STATE_RUNNING,
    /** @brief 准备停止，等待队列中所有消息全部处理完后会自动切换到MQ_STATE_STOPPED */
    MQ_STATE_PREPARE_STOP,
    /** @brief 停止中，等待任务线程退出 */
    MQ_STATE_STOPPING,
    /** @brief 任务线程已停止 */
    MQ_STATE_STOPPED,
} tMQ_STATE;

/** @brief 消息队列结构体定义 */
typedef struct {
    /** @brief 消息队列名称 */
    char name[MESSAGE_QUEUE_NAME_MAX_LEN];
    /** @brief 存储消息的优先级队列 */
    tPRIORITY_QUEUE pq;
    /** @brief 消息队列的状态 */
    tMQ_STATE state;
    /** @brief 消息队列的互斥锁 */
    tMUTEX mutex;
    /** @brief 消息队列的工作线程句柄数组 */
    tTHREAD thread[MESSAGE_QUEUE_MAX_THREAD_COUNT];
    /** @brief 消息队列的消息处理函数 */
    tMQ_HANDLE handle;
    /** @brief 消息队列的清理函数 */
    tMQ_CLEANUP cleanup;
    /** @brief 消息队列工作线程数量，取值范围：[1,MESSAGE_QUEUE_MAX_THREAD_COUNT] */
    uint8_t thread_count;
    /** @brief 已经启动的工作线程数量 */
    uint8_t running_thread_count;
#if MESSAGE_QUEUE_MAX_THREAD_COUNT > 1
    /** @brief 需要等待的消息列表，用于保证同一类型消息(what值相同)同一时间只能执行一个，进而保证执行顺序 */
    int64_t msg_wait_list[MESSAGE_QUEUE_MAX_THREAD_COUNT];
#endif
} tMESSAGE_QUEUE;
/**
 * @brief 初始化支持多线程的消息队列的宏定义
 * @param _mq_name 消息队列名称
 * @param _thread_count 消息队列的工作线程数量，取值范围：[1,MESSAGE_QUEUE_MAX_THREAD_COUNT]
 */
#define MQ_INIT_VAL_MT(_mq_name, _thread_count) {.name = _mq_name, .mutex = MUTEX_INIT_VAL(_mq_name), .thread_count = _thread_count}
/**
 * @brief 初始化单线程消息队列的宏定义
 * @param _mq_name 消息队列名称
 */
#define MQ_INIT_VAL(_mq_name) MQ_INIT_VAL_MT(_mq_name, 1)

/**
 * @brief 初始化消息队列
 *
 * @note 只是初始化队列，不启动任务线程
 * @note 调用此函数前, 请确保mq->state == MQ_STATE_NOT_INIT
 *
 * @param mq 需要初始化的消息队列指针,必须是未初始化过的否则返回失败
 * @param name 消息队列名称, 不可以为NULL
 * @param handle 消息处理函数, 使用mq_alloc_msg分配的消息默认使用此函数处理
 * @param cleanup 消息清理函数, tMQ_MSG中的args字段使用此函数清理
 *
 * @return true 成功, false 失败
 *
*/
bool mq_init(tMESSAGE_QUEUE *mq, tMQ_HANDLE handle, tMQ_CLEANUP cleanup);
/**
 * @brief 销毁消息队列
 *
 * 销毁消息队列, 如果队列已经运行，则先停止队列，之后会清空队列
 * 销毁消息队列时，会调用清理函数清理所有消息
 *
 * @param mq 消息队列指针
 *
 * @return 成功返回true, 失败返回false
*/
bool mq_deinit(tMESSAGE_QUEUE *mq);
/**
 * @brief 启动消息队列
 *
 * @note 消息队列启动后才可以发送消息
 *
 * @param mq 消息队列指针
 *
 * @return 如果启动成功返回true, 失败返回false（如果消息队列已启动或是未初始化也返回false）
 *
*/
bool mq_start(tMESSAGE_QUEUE *mq);
/**
 * @brief 停止消息队列
 *
 * 停止消息队列，调用后还未处理的消息将不再处理，之后会清空队列
 * @note 会等待任务线程退出后函数才返回
 *
 * @param mq 消息队列指针
 *
 * @return 成功返回true, 失败返回false
*/
bool mq_stop(tMESSAGE_QUEUE *mq);
/**
 * @brief 停止消息队列，并且等待消息队列中的所有消息都处理完毕
 *
 * @note 注意，此函数会等待所有消息都处理完毕，如果消息队列中存在大量消息，则等待时间会很长
 * @note 会等待任务线程退出后函数才返回
 *
 * @param mq 消息队列指针
 *
 * @return 成功返回true, 失败返回false
*/
bool mq_wait_stop(tMESSAGE_QUEUE *mq);
/**
 * @brief 分配一个MSG，并使用消息队列的清理函数和处理函数
 *
 * @param mq 消息队列指针
 *
 * @return 成功返回MSG指针，失败返回NULL
*/
tMQ_MSG *mq_alloc_msg(tMESSAGE_QUEUE *mq);
/**
 * @brief 释放MSG, 并调用其清理函数清理args参数
 *
 * @param msg 消息指针
*/
void mq_free_msg(tMQ_MSG *msg);
/**
 * @brief 向消息队列中发送一个立即处理的消息
 *
 * @note 消息队列需要处于运行状态，否则发送失败
 * @note 发送成功后消息队列会管理msg的释放，外部不要再释放msg
 *
 * @param mq 消息队列指针
 * @param msg 消息指针
 *
 * @return 成功返回true, 失败返回false
*/
bool mq_send_msg(tMESSAGE_QUEUE *mq, tMQ_MSG *msg);
/**
 * @brief 向消息队列中发送一个延迟处理的消息
 *
 * @note 消息队列需要处于运行状态，否则发送失败
 * @note 发送成功后消息队列会管理msg的释放，外部不要再释放msg
 *
 * @param mq 消息队列指针
 * @param msg 消息指针
 * @param delay_time 延迟时间，单位为毫秒
*/
bool mq_send_msg_delay(tMESSAGE_QUEUE *mq, tMQ_MSG *msg, uint64_t delay_time);
/**
 * @brief 发送一个立即处理的空消息
 *
 * 空消息是指msg的arg参数都未设置只有what的消息，一般是为了触发某些事件
 *
 * @note 消息队列需要处于运行状态，否则发送失败
 * @note 发送成功后消息队列会管理msg的释放，外部不要再释放msg
 *
 * @param mq 消息队列指针
 * @param what 消息类型
 *
 * @return 成功返回true, 失败返回false
*/
bool mq_send_empty_msg(tMESSAGE_QUEUE *mq, uint32_t what);
/**
 * @brief 发送一个延迟处理的空消息
 *
 * 空消息是指msg的arg参数都未设置只有what的消息，一般是为了触发某些事件
 *
 * @note 消息队列需要处于运行状态，否则发送失败
 * @note 发送成功后消息队列会管理msg的释放，外部不要再释放msg
 *
 * @param mq 消息队列指针
 * @param what 消息类型
 * @param delay_time 延迟时间，单位为毫秒
 *
 * @return 成功返回true, 失败返回false
*/
bool mq_send_empty_msg_delay(tMESSAGE_QUEUE *mq, uint32_t what, uint32_t delay_time);
/**
 * @brief 发送一个延时处理的带参数的消息
 *
 * @note 消息队列需要处于运行状态，否则发送失败
 *
 * @param mq 消息队列指针
 * @param what 消息类型
 * @param arg1 参数1
 * @param arg2 参数2
 * @param args 指针参数
 * @param delay_time 延迟时间，单位为毫秒
 *
 * @return 成功返回true, 失败返回false
*/
bool mq_send_msg_with_args_delay(tMESSAGE_QUEUE *mq, uint32_t what, uint32_t arg1, uint64_t arg2, void *args, uint32_t delay_time);
/**
 * @brief 发送一个立即处理的带参数的消息
 *
 * @note 消息队列需要处于运行状态，否则发送失败
 *
 * @param mq 消息队列指针
 * @param what 消息类型
 * @param arg1 参数1
 * @param arg2 参数2
 * @param args 指针参数
 *
 * @return 成功返回true, 失败返回false
*/
bool mq_send_msg_with_args(tMESSAGE_QUEUE *mq, uint32_t what, uint32_t arg1, uint64_t arg2, void *args);
/**
 * @brief 移除消息队列中指定类型的所有消息
 *
 * @param mq 消息队列指针
 * @param what 消息类型
 *
 * @return 成功返回true, 失败返回false
*/
bool mq_remove_msg(tMESSAGE_QUEUE *mq, uint32_t what);
/**
 * @brief 清空消息队列
 *
 * @note 必须保证消息队列处于运行状态，否则清空失败
 *
 * @param mq 消息队列指针
 *
 * @return 成功返回true, 失败返回false
*/
bool mq_clear(tMESSAGE_QUEUE *mq);

#endif /* _MESSAGE_QUEUE_H_ */
